using System;
using csvorbis;

namespace Clandestine.Audio
{
	// A basic Ogg Vorbis decoder, using the simplified-ish libVorbisfile interface.
	[DecoderHandlesFileType(new string[] { "ogg" })]
	internal class VorbisfileDecoder : Decoder
	{
		VorbisFile vf;
		Info inf;
		
		#region implemented abstract members of Clandestine.Audio.Decoder
		public override bool TryStartDecode (string filename)
		{
			vf = new VorbisFile(filename);
			Info inf = vf.getInfo(-1);
			
			switch (inf.channels)
			{
				case 1:
					channels = Channels.Mono;
					break;
				case 2:
					channels = Channels.Stereo;
					break;
				default:
					Console.WriteLine("VorbisFile reports not mono & not stereo file, so not loading.");
					return false;
			}
			
			if (!vf.seekable())
			{
				Console.WriteLine("VorbisFile reports " + filename + " is NOT seekable.  Not loading.");
				return false;
			}
			
			length = TimeSpan.FromSeconds(vf.time_total(-1));
			rate = inf.rate;
			//inf.clear();
			return true;
		}
		
		
		public override void EndDecode()
		{
			// TODO: Figure out wtf supposed to do here
			inf.clear(); // ???
		}
		
		
		public override void Rewind()
		{
			if (vf.raw_seek(0) != 0)
				Console.WriteLine("VorbisFile: Seek failure.");
			eos = false;
		}
		
		
		Channels channels;
		public override Channels Channels
		{
			get { return channels; }
		}
		
		TimeSpan length;
		public override TimeSpan Length
		{
			get { return length; }
		}
		
		int rate;
		public override int Rate
		{
			get { return rate; }
		}
		
		bool eos = false;
		public override bool EndOfStream
		{
			get { return eos; }
		}
		
		public override byte[] DecodeChunkPCM16bit()
		{
			byte[] xbuf = new byte[StreamingBuffer.PreferredDecodeSize];
			byte[] tmp = new byte[StreamingBuffer.PreferredDecodeSize];
			
			int read = 1;
			int sum = 0;
			int[] gahhh = new int[1];
			
			while (read > 0 && sum < xbuf.Length)
			{
				read = vf.read(tmp, xbuf.Length - sum, 0, 2, 1, gahhh);
				if (read > 0)
				{
					Array.Copy(tmp, 0, xbuf, sum, read);
					sum += read;
				}
				
				//Console.WriteLine("Vorbisfile: Now got " + sum.ToString() + " bytes.");
			}
			
			//Console.WriteLine("NOW SERVING " + sum.ToString() + " BYTES.");
			
			if (sum <= 0)
			{
				eos = true;
				xbuf = null;
			}
			//else if (sum == xbuf.Length)
			//	return xbuf;
			else
			{
				Array.Resize<byte>(ref xbuf, sum);
				//eos = true;
				//return xbuf;
			}
			
			if (this.Loop)
			{
				if (eos)
					this.Rewind();
				if (xbuf == null)
					return DecodeChunkPCM16bit();
			}
			else if (xbuf == null)
				return new byte[0];
			
			return xbuf;
		}
		
		#endregion

	}
}

